package seatiger.tomcat.catalina.core;

import seatiger.tomcat.catalina.*;
import seatiger.tomcat.catalina.connector.NewRequest;
import seatiger.tomcat.catalina.connector.NewResponse;
import seatiger.tomcat.catalina.deploy.FilterDef;
import seatiger.tomcat.catalina.deploy.FilterMap;

import javax.servlet.*;
import java.io.IOException;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 *  StandardWrapper 的基础阀实现
 */
public class StandardWrapperValve extends ValveBase {
    private static final String info =
            "seatiger.tomcat.catalina.core.StandardWrapperValve/1.0";
    @Override
    public String getInfo() {
        return info;
    }
    @Override
    @Deprecated
    public void invoke(Request request, Response response, ValveContext context) throws IOException, ServletException {
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = wrapper.allocate();
        ApplicationFilterChain filterChain = createFilterChain(servlet);
        ServletRequest sreq = request.getRequest();
        ServletResponse sres = response.getResponse();
        filterChain.doFilter(sreq, sres);
    }

    @Override
    public void invoke(NewRequest request, NewResponse response) throws IOException, ServletException{
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = wrapper.allocate();
        ApplicationFilterChain filterChain = createFilterChain(servlet);
        filterChain.doFilter(request.getRequest(), response.getResponse());
    }

    private ApplicationFilterChain createFilterChain(Servlet servlet){
        ApplicationFilterChain filterChain = new ApplicationFilterChain();
        filterChain.setServlet(servlet);
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Context context = (Context) wrapper.getParent();
        String servletName = wrapper.getName();
        getFilterConfigs(filterChain,context,filterMap -> filterMap.getServletName().equals(servletName));
        return filterChain;
    }

    private void getFilterConfigs(ApplicationFilterChain filterChain,Context context, Predicate<FilterMap> predicate){
        List<FilterMap> filterMaps = context.findFilterMaps();
        filterMaps.stream()
                .filter(filterMap -> predicate.test(filterMap))
                .forEach(filterMap -> {
                    FilterConfig filterConfig = context.findFilterConfig(filterMap.getFilterName());
                    filterChain.addFilter(filterConfig);
                });
    }
}
